package block

import (
	"bytes"
	"crypto/sha256"
	"encoding/gob"
	"fmt"
	"log"
	"time"
)

//1.定义区块结构
type Block struct {
	Version uint64 // 区块链版本号

	PrevBlockHash []byte //>1.前区块哈希

	MerKleRoot []byte // 先填写为空 后续v4使用

	TimeStamp uint64 // 时间戳

	Difficulity uint64 //挖矿难度

	Nonce uint64 //随机数，挖矿找的就是他

	Hash []byte //>2.当前区块哈希，区块不存在该字段，为了方便查看改测试中使用
	//Data []byte //>3.数据 v4开始使用区块数据交易代替 ，
	Transactions []*Transaction //区块体，上面是区块头
}

//2.创建区块
func NewBlock(txs []*Transaction, prevBlockHash []byte) *Block {
	block := Block{
		Version:       00,
		PrevBlockHash: prevBlockHash,
		MerKleRoot:    []byte{},
		TimeStamp:     uint64(time.Now().Unix()),
		Difficulity:   Bits, // 定义难度
		Nonce:         10,
		Hash:          []byte{}, //后续填充数据
		//Data:          []byte(data),
		Transactions: txs,
	}
	// 生成区块时，立即做哈希处理，这样最干净
	////v1
	//block.ProcessingHash()
	//v2
	//v5
	block.HashTransactions()
	fmt.Println("创建新区块中。。")
	pow := NewProofOfWork(&block)
	hash, nonce := pow.Run() // 计算和校验
	block.Hash = hash
	block.Nonce = nonce
	return &block
}

//3.生成哈希
/**
func (block *Block) ProcessingHash() {
	//data := []byte{}

	// 方法1.一个一个添加到data字节数组里面，然后统一做hash处理
	//data = append(data, utils.UintToByte(block.Version)...)
	//data = append(data, block.PrevBlockHash...)
	//data = append(data, block.MerKleRoot...)
	//data = append(data, utils.UintToByte(block.TimeStamp)...)
	//data = append(data, utils.UintToByte(block.Difficulity)...)
	//data = append(data, block.Data...)
	//data = append(data, utils.UintToByte(block.Nonce)...)

	// 方法2.使用bytes.join
	tmp := [][]byte{
		utils.UintToByte(block.Version),
		block.PrevBlockHash,
		block.MerKleRoot,
		utils.UintToByte(block.TimeStamp),
		utils.UintToByte(block.Difficulity),
		block.Transaction,
		utils.UintToByte(block.Nonce),
	}
	data2 := bytes.Join(tmp, []byte{})
	// 做区块hash处理
	hash := sha256.Sum256(data2)
	block.Hash = hash[:]
}
*/
// 将block序列化，保证传输以及储存效率
func (block *Block) Serialization() []byte {
	var buffer bytes.Buffer
	// 创建新的编码器
	encoder := gob.NewEncoder(&buffer)
	// 使用编码器
	err := encoder.Encode(block)
	if err != nil {
		log.Panic(err)
	}
	// 返回序列化完成的bytes
	return buffer.Bytes()
}

// 将block反序列化，保证传输以及储存效率
func Deserialization(by []byte) *Block {
	//fmt.Println("解码传入数据=", by)
	// 创建新的解码器
	decoder := gob.NewDecoder(bytes.NewBuffer(by))
	//使用编码器
	var block Block
	err := decoder.Decode(&block)
	if err != nil {
		log.Panic(err)
	}
	return &block
}

/**
模拟梅克尔根（比特币哈希），做一个简单的,替换掉上面的ProcessingHash
 */
func (block *Block)HashTransactions()  {
	// 模拟我们交易的id就是交易的哈希值，所以我们拼接交易id，做哈希运算
	var hashs []byte
	for _,tx:=range block.Transactions{
		txid:=tx.TXid
		hashs=append(hashs,txid...)
	}
	hash:=sha256.Sum256(hashs)
	block.MerKleRoot=hash[:]
}
